#include "StdAfx.h"
#include "cln_connection.hpp"
#include "cln_conn_manager.hpp"

namespace fly {

	namespace jld{

		namespace client
		{
			connection::connection(boost::asio::io_service& io_service,
				connection_manager& manager, cln_handler* handler)
				:socket_(io_service),
				connection_manager_(manager),
				recv_buf_(),
				send_buf_(),
				info_(),
				handler_(handler)
			{
			}

			connection::~connection()
			{
				LOG_INFO("Destroy connection");
			}

			boost::asio::ip::tcp::socket& connection::socket()
			{
				return socket_;
			}
			void connection::stop()
			{
				socket_.close();
			}

			cln_info& connection::info()
			{
				return info_;
			}

			void connection::start()
			{
				asyn_write();
				read_header();
			}

			void connection::asyn_write()
			{
				//prepare for send
				handler_->handle_send(recv_buf_, send_buf_, info_);
				if (send_buf_.is_send())
				{
					boost::asio::async_write(socket_, *send_buf_.packets().front().buf,
						boost::bind(&connection::handle_write, shared_from_this(),
						boost::asio::placeholders::error,
						boost::asio::placeholders::bytes_transferred));
					send_buf_.packets().pop();
				}

			}
			void connection::handle_write(const boost::system::error_code& err,std::size_t bytes_transferred)
			{
				if (err)
				{
					LOG_T_ERR(err.message());
					connection_manager_.stop(shared_from_this());
				}
			}

			void connection::read_header()
			{
				boost::asio::async_read(socket_, recv_buf_.buf(),
					boost::asio::transfer_exactly(recv_buf_.header_size()),
					boost::bind(&connection::handle_header_read, shared_from_this(),
					boost::asio::placeholders::error,
					boost::asio::placeholders::bytes_transferred));
			}
			void connection::handle_header_read(const boost::system::error_code& err,std::size_t bytes_transferred)
			{
				if (!err)
				{
					if (!recv_buf_.handle_header())
					{
						connection_manager_.stop(shared_from_this());
						return;
					}
					read_body();
				}
				else
				{
					LOG_T_ERR(err.message());
					connection_manager_.stop(shared_from_this());
				}
			}

			void connection::read_body()
			{
				boost::asio::async_read(socket_, recv_buf_.buf(),
					boost::asio::transfer_exactly(recv_buf_.body_size()),
					boost::bind(&connection::handle_body_read, shared_from_this(),
					boost::asio::placeholders::error,
					boost::asio::placeholders::bytes_transferred));
			}
			void connection::handle_body_read(const boost::system::error_code& err,std::size_t bytes_transferred)
			{
				if (!err)
				{
					if (!handler_->handle_recv(recv_buf_, send_buf_, info_))
					{
						connection_manager_.stop(shared_from_this());
						return;
					}

					asyn_write();
					read_header();
				}
				else
				{
					LOG_T_ERR(err.message());
					connection_manager_.stop(shared_from_this());
				}
			}
		}

	}
}